#include "rotkoerper.h"

#define deltaX 1e-6

// rotmax: entspricht den Slices, also der Anzahl der Laengsunterteilungen
const int rotmax = 50; // (nur gerade Zahlen moeglich!)
/* 
 * Der Poller wird 2.2 Einheiten hoch, die Funktion ist darauf ausgerichtet.
 * Die Anzahl der Stacks ist verdoppelt worden, deshalb ist die 'hoehe' hier gleich 44, sonst 22.
 */
const int hoehe = 44;

datatypes::Vector3D vertices[(rotmax-1)+(hoehe-1)*(rotmax)+1];
datatypes::Vector3D normals[(rotmax-1)+(hoehe-1)*(rotmax)+1];
datatypes::Vector2D texturCoods[(rotmax-1)+(hoehe-1)*(rotmax)+1];

/* 
 * Die Funktion f fuer den Rotationskoerper 'Poller' teilt sich in drei Teile auf:
 * 1. fuer (x < 1.7)         :  3/4 * x + 0.5,   (quasi eine Gerade fast parallel zur x-Achse)
 * 2. fuer (1.7 <= x < 2.0)  :  sin(4*(x+0.1)),  (eine halbe Sinus-Schwingung)
 * 3. fuer (x >= 2.0)        :  -5x + 11         (quasi eine Gerade fast parallel zur y-Achse)
 * 
 */
   float f(float x) {
	if(x<1.7) return ((3/4) * x) + 0.5;
	else if(x<2.0) return (sin(4*(x+0.1)));
	else return -5.0 * x + 11.0;
}

/* 
 * Die Ableitung f' der Funktion f:
 * 1. fuer (x < 1.7)         :  3/4,
 * 2. fuer (1.7 <= x < 2.0)  :  4 * cos(4*(x+0.1)),
 * 3. fuer (x >= 2.0)        :  -5
 * 
 */
float f_(float x) {
	if(x<1.7) return (3/4);
	else if(x<2.0) return 4*cos(4*(x+0.1));
	else return -5.0;
	//return (f(x + deltaX) - f(x)) / (deltaX); // <--- numerische Abl.
}

/*
 * Die Vertices fuer den Poller werden hier initialisiert.
 * @StackAbstand: entspricht quasi den Stacks, also den Breitenunterteilungen.
 *                Je kleiner der Wert desto mehr Stacks, Variable 'hoehe' muss
 *                darauf angepasst werden!
 *
 *        GL_TRIANGLE_STRIP:
 *
 *          /\/\/\/\/\/\/\/\    <- t=hoehe
 *        /\/\/\/\/\/\/\/\/\/\
 *            /\/\/\/\/\/\
 *            /\/\/\/\/\/\
 *            /\/\/\/\/\/\
 *            /\/\/\/\/\/\
 *            /\/\/\/\/\/\      <- t=0
 */
void init_poller() {
	float tf = 0.0;
	float stackAbstand = 0.05;
	for(int t=0; t<hoehe; t++) {
		for(int i=0;i<rotmax;i++) {
			// Der Winkel theta, insgesamt Drehung um 360 Grad
			GLfloat theta = ((2*M_PI*i)/(rotmax-2));

			/* 
			 * Hier werden die Vertices fuer das GL_TRIANGLE_STRIP 
			 * auf der aktuell 'unteren Ebene' gesetzt.
			 */
			vertices[i+t*rotmax].x = sinf(theta) * f(tf);
			vertices[i+t*rotmax].y = tf;
			vertices[i+t*rotmax].z = cosf(theta) * f(tf);

			/* 
			 * Hier werden die Normalen fuer die aktuell 'unteren Vertices' gesetzt.
			 */
			normals[i+t*rotmax].x  = sinf(theta) * f(tf);
			normals[i+t*rotmax].y  = -f(tf) * f_(tf);
			normals[i+t*rotmax].z  = cosf(theta) * f(tf);
			mathfunctions::normalizeVector(normals[i+t*rotmax]);

			/* 
			 * Hier werden die Textur-Koordinaten gesetzt.
			 */
			texturCoods[i+t*rotmax].x  = sinf(theta) * f(tf);
			texturCoods[i+t*rotmax].y  = tf / (hoehe * stackAbstand);
			
			/*
			 * 'Ebene' wird erhoeht und es werden erneut Vertices, 
			 * Normalen und Textur-Koordinaten gesetzt.
			 */
			i++;
			vertices[i+t*rotmax].x = sinf(theta) * f(tf+stackAbstand);
			vertices[i+t*rotmax].y = tf+stackAbstand;
			vertices[i+t*rotmax].z = cosf(theta) * f(tf+stackAbstand);
		
			normals[i+t*rotmax].x  = sinf(theta) * f(tf+stackAbstand);
			normals[i+t*rotmax].y  = -f(tf+stackAbstand) * f_(tf+stackAbstand);
			normals[i+t*rotmax].z  = cosf(theta) * f(tf+stackAbstand);
			mathfunctions::normalizeVector(normals[i+t*rotmax]);

			texturCoods[i+t*rotmax].x  = sinf(theta) * f(tf+stackAbstand);
			texturCoods[i+t*rotmax].y  = (tf + stackAbstand) / (hoehe * stackAbstand);
		}
		tf += stackAbstand;
	}
}

/*
 * Hier wird der Poller nun letztendlich gezeichnet 
 * (unter Verwendung der vorher initialisierten Arrays)
 * 
 */
void draw_poller() {
	glEnableClientState(GL_VERTEX_ARRAY);
	glEnableClientState(GL_NORMAL_ARRAY);
	glEnableClientState(GL_TEXTURE_COORD_ARRAY);

	glVertexPointer(3,GL_FLOAT,0,vertices);
	glNormalPointer(GL_FLOAT,0,normals);
	glTexCoordPointer(2, GL_FLOAT, 0, texturCoods);

	OGL_Set_Current_Texture_Map(poller_64, 1.00000f, 1.00000f, 0.000000f, 0.000000f);
	glDrawArrays(GL_TRIANGLE_STRIP, 0, (rotmax-1)+(hoehe-1)*(rotmax)+1);

	//Funktion zum Anzeigen der Normalen
	/*
	glLineWidth(1.0);
	glBegin(GL_LINES);
	for(int i=0; i< ((rotmax-1)+(hoehe-1)*(rotmax)+1); i++) {
		glVertex3f(vertices[i].x, vertices[i].y, vertices[i].z);
		glVertex3f(vertices[i].x+normals[i].x, vertices[i].y+normals[i].y, vertices[i].z+normals[i].z);
	}
	glEnd();
	*/

	glDisableClientState(GL_VERTEX_ARRAY);
	glDisableClientState(GL_NORMAL_ARRAY);
	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}

// der gleiche Poller nur fuer den Steg mit einer anderen Textur
// ist nicht schoen. Am besten man koennte die Textur als Paramater
// uebergeben
void draw_steg_poller()
{
  glEnableClientState(GL_VERTEX_ARRAY);
  glEnableClientState(GL_NORMAL_ARRAY);
  glEnableClientState(GL_TEXTURE_COORD_ARRAY);

  glVertexPointer(3,GL_FLOAT,0,vertices);
  glNormalPointer(GL_FLOAT,0,normals);
  glTexCoordPointer(2, GL_FLOAT, 0, texturCoods);

  OGL_Set_Current_Texture_Map(steg_poller, 1.00000f, 1.00000f, 0.000000f, 0.000000f);
  glDrawArrays(GL_TRIANGLE_STRIP, 0, (rotmax-1)+(hoehe-1)*(rotmax)+1);

  //Funktion zum Anzeigen der Normalen
/*glLineWidth(1.0);
  for(int i=0; i< ((rotmax-1)+(hoehe-1)*(rotmax)+1); i++) {
     glBegin(GL_LINES);
	glVertex3f(vertices[i].x, vertices[i].y, vertices[i].z);
	glVertex3f(vertices[i].x+normals[i].x, vertices[i].y+normals[i].y, vertices[i].z+normals[i].z);
     glEnd();
  }*/

  glDisableClientState(GL_VERTEX_ARRAY);
  glDisableClientState(GL_NORMAL_ARRAY);
  glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
